package cn.xeblog.server.action.handler;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.xeblog.commons.entity.User;
import cn.xeblog.commons.entity.react.React;
import cn.xeblog.commons.entity.react.request.AdminReact;
import cn.xeblog.commons.entity.react.result.AdminReactResult;
import cn.xeblog.commons.entity.react.result.ReactResult;
import cn.xeblog.commons.enums.Permissions;
import cn.xeblog.server.action.ChannelAction;
import cn.xeblog.server.action.specialAc.ActionCounter;
import cn.xeblog.server.action.specialAc.SpecialCommandHandler;
import cn.xeblog.server.action.timer.TimerAction;
import cn.xeblog.server.action.timer.TimerUtil;
import cn.xeblog.server.builder.ResponseBuilder;
import cn.xeblog.server.cache.UserCache;
import cn.xeblog.server.factory.ReactHandlerFactory;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author ZhangLei
 * @date 2024/2/5 14:34
 */
@Slf4j
public class VoteHandler {

    /*
        1：第一个人输入【发起投票】，系统开始计时【5】秒，【5】秒内有【5】个人都打出【投票】，系统正式发起投票。
        2：系统给出投票选项【1:禁言;2:踢下线;3:xxx】，并开始计时【60】秒。
        3：计时时间内，在线用户可以发送【投票:::[数字选项]:::[用户名]】发起投票，每人仅投票一次
        4：计时结束，票数最高的用户，则按选项被系统执行相应操作
     */

    private final static String DELIMITER = ":::";
    private static int VOTE_TIME_PRE = 20;
    private static int VOTE_TIME = 60;
    // 下限
    private static int VOTE_USER_NUM = 4;
    private static double VOTE_USER_PROPORTION = 0.3;

    /**
     * 缓存可投票的用户
     */
    private final static Map<String, User> voteMap = new HashMap<>();
    /**
     * 投票数据
     */
    private final static Map<String, String> voteResultMap = new HashMap<>();

    /**
     * 投票状态
     */
    public volatile static boolean voteCheckFlag = false;
    public volatile static boolean voteFlag = false;

    private static void refreshConfig() {
        try {
            String json = FileUtil.readString("/home/xechat/config/config.json", StandardCharsets.UTF_8);
            JSONObject configObj = JSONObject.parseObject(json);

            JSONObject userKeys = configObj.getJSONObject("voteKeys");
            VOTE_TIME = userKeys.getIntValue("VOTE_TIME");
            VOTE_USER_NUM = userKeys.getIntValue("VOTE_USER_NUM");
            VOTE_USER_PROPORTION = userKeys.getDoubleValue("VOTE_USER_PROPORTION");
            VOTE_TIME_PRE = userKeys.getIntValue("VOTE_TIME_PRE");
        } catch (Exception e) {
            log.info("投票配置解析异常！", e);
        }
    }

    /**
     * 开启投票验证
     */
    public static void startVotePre() {

        if (VOTE_USER_NUM > UserCache.listUser().size()) {
            ChannelAction.send(ResponseBuilder.system("投票未开启，用户数量不足！至少需要" + VOTE_USER_NUM + "人开启。"));
            return;
        }

        if (voteCheckFlag) {
            ChannelAction.send(ResponseBuilder.system("投票验证进行中！不能重复发起！"));
            return;
        }

        refreshConfig();

        // 初始化可投票用户
        voteMap.clear();
        voteMap.putAll(UserCache.listUser().stream().collect(Collectors.toMap(User::getIp, Function.identity(), (k1, k2) -> k1)));
        voteCheckFlag = true;
        voteResultMap.clear();

        TimerUtil.startTimer(new TimerAction() {
            @Override
            public void timingBegins(Date overTime) {
                long secondsLeft = (overTime.getTime() - new Date().getTime()) / 1000;
                List<Long> seconds = Lists.newArrayList(1L, 3L, 9L);
                if (seconds.contains(secondsLeft) || VOTE_TIME_PRE - 2 == secondsLeft) {
                    String tips = StrUtil.format("正在检测是否发起投票...剩余时间{}秒。", secondsLeft);
                    ChannelAction.send(ResponseBuilder.system(tips));
                }
            }

            @Override
            public void timingEnds(Date overTime) {
                if (checkStartVote()) {
                    startVote();
                } else {
                    long startTimes = getStartTimes();
                    String tips = StrUtil.format("未达到开启投票标准，不开启投票。需{}秒内{}人都发“发起投票”。", VOTE_TIME_PRE, startTimes == 99999 ? VOTE_USER_NUM : startTimes);
                    ChannelAction.send(ResponseBuilder.system(tips));
                    voteCheckFlag = false;
                }
            }
        }, VOTE_TIME_PRE);

    }

    /**
     * 校验是否开启投票
     */
    private static boolean checkStartVote() {
        // 清理无效投票
        voteResultMap.keySet().removeIf(k -> !voteMap.containsKey(k));
        // 统计
        long count = voteResultMap.values().stream().filter("发起投票"::equals).count();
        return count >= getStartTimes();
    }

    /**
     * 获取投票人次
     */
    private static long getStartTimes() {
        int size = voteMap.keySet().size();
        if (size < VOTE_USER_NUM) {
            return 99999;
        }
        long round = Math.round(size * VOTE_USER_PROPORTION);
        return Math.max(VOTE_USER_NUM, round);
    }

    /**
     * 开启投票，计时开始
     */
    private static void startVote() {

        if (voteFlag) {
            String warnMsg = "已有投票进行中！不能重复发起投票！";
            ChannelAction.send(ResponseBuilder.system(warnMsg));
            return;
        }

        voteFlag = true;

        voteResultMap.clear();

        String startMsg = "开启投票！请在" + VOTE_TIME + "秒内，发送【投票:::[数字选项]:::[被投票用户名]】发起投票，每人仅投票一次，可用投票选项：1:禁言;2:解除禁言；3:踢下线。";
        ChannelAction.send(ResponseBuilder.system(startMsg));
        TimerUtil.startTimer(new TimerAction() {
            @Override
            public void timingBegins(Date overTime) {
                long secondsLeft = (overTime.getTime() - new Date().getTime()) / 1000;
                List<Long> seconds = Lists.newArrayList(1L, 3L, 5L, 10L);
                if (secondsLeft % 20 == 0) {
                    String tips = StrUtil.format("投票进行中...剩余时间{}秒。", secondsLeft);
                    ChannelAction.send(ResponseBuilder.system(tips));
                } else if (seconds.contains(secondsLeft)) {
                    String tips = StrUtil.format("投票即将结束...剩余时间{}秒。", secondsLeft);
                    ChannelAction.send(ResponseBuilder.system(tips));
                }
            }

            @Override
            public void timingEnds(Date overTime) {
                doAction();

                voteResultMap.clear();
                voteCheckFlag = false;
                voteFlag = false;
            }
        }, VOTE_TIME);

    }

    private static void doAction() {
        // 清理无效投票
        voteResultMap.keySet().removeIf(k -> !voteMap.containsKey(k));
        if (voteResultMap.values().isEmpty()) {
            ChannelAction.send(ResponseBuilder.system("投票数据为空，无事发生。"));
            return;
        }

        ActionCounter counter = new ActionCounter();
        for (String value : voteResultMap.values()) {
            String[] split = value.split(DELIMITER);
            counter.recordAction(Integer.parseInt(split[1]), split[2]);
        }

        Integer actionNum = counter.getMostFrequentAction();
        String username = counter.getPersonWithMostActionsIn(actionNum);

        User user = UserCache.getUserByUsername(username);
        if (user == null) {
            String tips = StrUtil.format("投票结束！用户【{}】不存在", username);
            ChannelAction.send(ResponseBuilder.system(tips));
            return;
        }

        String action = "无效选项";
        switch (actionNum) {
            case 1:
                action = "禁言";
                adminReact(AdminReact.Operate.USER_PERMIT_REMOVE, user.getId());
                break;
            case 2:
                action = "解除禁言";
                adminReact(AdminReact.Operate.USER_PERMIT_ADD, user.getId());
                break;
            case 3:
                action = "踢下线三分钟";

                // 踢下线后拉黑三分钟
                TimerUtil.startTimer(new TimerAction() {
                    @Override
                    public void timingBegins(Date overTime) {
                        SpecialCommandHandler.blackControlAdd(user);
                    }

                    @Override
                    public void timingEnds(Date overTime) {
                        SpecialCommandHandler.blackControlRemove(user);
                    }
                }, 180);

                ChannelAction.forceOffline(user);
                break;
            default:
                break;
        }

        String tips = StrUtil.format("投票结束！即将执行的是【{}】，被执行的用户是【{}】", action, username);
        ChannelAction.send(ResponseBuilder.system(tips));
    }

    @SuppressWarnings("unchecked")
    private static void adminReact(AdminReact.Operate operate, String uid) {
        User system = new User();
        system.setIp("127.0.0.1");
        system.setId("11111111111111111111system");
        system.setRole(User.Role.ADMIN);

        ReactResult<AdminReactResult> result = new ReactResult<>();
        ReactHandlerFactory.INSTANCE.produce(React.ADMIN).handle(system, new AdminReact(operate, Permissions.ALL, uid), result);
        log.info("投票权限结果：{}", JSONObject.toJSONString(result));
    }

    public static void addUser(User user, String msg) {
        voteResultMap.put(user.getIp(), msg);
    }

    public static void addVote(User user, String msg) {
        if (!voteFlag) {
            user.send(ResponseBuilder.system("非投票时间！"));
        }

        String[] split = msg.split(DELIMITER);
        User voteUser = UserCache.getUserByUsername(split[2]);
        if (voteUser == null) {
            String tips = StrUtil.format("用户【{}】不存在！", split[2]);
            user.send(ResponseBuilder.system(tips));
        } else {
            voteResultMap.put(user.getIp(), msg);
        }
    }

}
